﻿using Action = Styx.TreeSharp.Action;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using Styx.Pathing;

namespace Kitty
{
    public partial class Main : CombatRoutine
    {
        #region begin Helpers
        public string LastSpell { get; set; }
        public int LastSpelID { get; set; }
        public string LastLog { get; set; }

        #region spellID's
        public int SAVAGEROAR = 52610;
        public int RAKE = 1822;
        public int RIP = 1079;
        public int FEROCIOUSBITE = 22568;
        public int MANGLE = 33876;
        public int WEAKENEDARMOR = 113746;
        public int FAERIEFIRE = 770;
        public int FAERIESWARM = 106707;
        #endregion spellID's


        #region Buffs
        Composite createBuffs()
        {
            return new PrioritySelector(
                new Decorator(ret => PauseAoe, crPaused()),
                CastBuff("Mark of the Wild", "Mark of the Wild", 2 , ret => SpellManager.HasSpell("Mark of the Wild")
                    && !buffExists("Mark of the Wild", Me)
                    && !buffExists("Legacy of the Emperor", Me)
                    && !buffExists("Blessing of Kings", Me)
                    && !buffExists("Embrace of the Shale Spider", Me)
                    && ((CRSettings.myPrefs.motw == CRSettings.CastMotW.NotInParty && Me.GroupInfo.IsInParty)
                    || (CRSettings.myPrefs.motw == CRSettings.CastMotW.AlwaysButNotInCombat && !Me.Combat)
                    || CRSettings.myPrefs.motw == CRSettings.CastMotW.Always)
                    && Me.Shapeshift != ShapeshiftForm.FlightForm
                    && !Me.Mounted
                    && !Me.IsFlying),
                CastBuff("Aquatic Form", "Aquatic Form", 2 , ret => SpellManager.HasSpell("Aquatic Form")
                    && Me.Shapeshift != ShapeshiftForm.Aqua
                    && !Me.Combat
                    && Me.IsSwimming
                    && !Me.Mounted
                    && !buffExists("Prowl", Me)),
                new Decorator(ret => gotTarget && MeRooted(), MeIsRooted()),
                new Decorator(ret => CRSettings.myPrefs.AlchemyFlask
                    && !buffExists("Enhanced Agility", Me)
                    && !buffExists("Crystal of Insanity", Me)
                    && !buffExists("Flask of Spring Blossoms", Me), useAlchemyFlask()),
                new Decorator(ret => gotTarget
                    && Me.Combat
                    && Me.HealthPercent <= CRSettings.myPrefs.healthstonepercent,
                    useHealthStone()),
                new Decorator(ret => CRSettings.myPrefs.useFlask
                    && Me.GroupInfo.IsInRaid
                    && Me.Combat
                    && !buffExists("Flask of Spring Blossoms", Me),
                    useFlask()),
                CastBuff("Might of Ursoc", "Might of Ursoc", 2 , ret => gotTarget
                    && SpellManager.HasSpell("Might of Ursoc")
                    && !spellOnCooldown("Might of Ursoc")
                    && Me.HealthPercent <= CRSettings.myPrefs.ursoc),
                Cast("Feral Spirit", "Feral Spirit",2, ret => gotTarget
                    && SpellManager.HasSpell("Feral Spirit")
                    && !spellOnCooldown("Feral Spirit")
                    && (CRSettings.myPrefs.feralSpirit == CRSettings.CooldownPrefs.OnCoolDown
                    || (CRSettings.myPrefs.feralSpirit == CRSettings.CooldownPrefs.Bosses && IsWoWBoss(Me.CurrentTarget)))
                    && Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Bone Shield", "Bone Shield", 2 , ret => gotTarget
                    && SpellManager.HasSpell("Bone Shield")
                    && !spellOnCooldown("Bone Shield")
                    && !buffExists("Bone Shield", Me)),
                CastBuff("Cat Form", "Cat Form", 2 , ret => SpellManager.HasSpell("Cat Form")
                    && Me.Combat
                    && Me.Specialization == WoWSpec.DruidFeral
                    && !buffExists("Might of Ursoc", Me)
                    && Me.Shapeshift != ShapeshiftForm.Cat
                    && !SwitchBearForm),
                CastBuff("Rejuvenation", "Rejuvenation", 2 , ret => SpellManager.HasSpell("Rejuvenation")
                    && !Me.Combat
                    && Me.HealthPercent <= CRSettings.myPrefs.RejuOoc),
                CastBuff("Healing Touch", "Healing Touch", 2, ret => SpellManager.HasSpell("Healing Touch")
                    && !Me.Combat
                    && Me.HealthPercent <= CRSettings.myPrefs.HealingTouchOoc),
                CastBuff("Cenarion Ward", "Cenarion Ward", 2, ret => gotTarget
                    && SpellManager.HasSpell("Cenarion Ward")
                    && Me.Combat
                    && !spellOnCooldown("Cenarion Ward")
                    && Me.HealthPercent <= CRSettings.myPrefs.CenarionWard
                    && LastSpell != "Cenarion Ward"),
                CastBuff("Barkskin", "Barkskin", 2, ret => gotTarget
                    && SpellManager.HasSpell("Barkskin")
                    && Me.Combat
                    && !spellOnCooldown("Barkskin")
                    && Me.HealthPercent <= CRSettings.myPrefs.Barkskin
                    && LastSpell != "Barkskin"),
                CastBuff("Survival Intstincts", "Survival Instincts", 2, ret => gotTarget
                    && SpellManager.HasSpell("Survival Instincts")
                    && Me.Combat
                    && !spellOnCooldown("Survival Instincts")
                    && Me.HealthPercent <= CRSettings.myPrefs.survivalInstincts),
                CastBuff("Frenzied Regeneration", "Frenzied Regeneration", 2, ret => gotTarget
                    && SpellManager.HasSpell("Frenzied Regeneration")
                    && Me.Combat
                    && Me.Shapeshift == ShapeshiftForm.Bear
                    && !spellOnCooldown("Frenzied Regeneration")
                    && Me.HealthPercent <= CRSettings.myPrefs.frenzied),
                CastBuff("Renewal", "Renewal", 2, ret => gotTarget
                    && SpellManager.HasSpell("Renewal")
                    && Me.Combat
                    && !spellOnCooldown("Renewal")
                    && Me.HealthPercent <= CRSettings.myPrefs.renewal),
                Cast("Nature's Vigil", "Nature's Vigil", 2, ret => gotTarget
                    && SpellManager.HasSpell("Nature's Vigil")
                    && Me.Combat
                    && !spellOnCooldown("Nature's Vigil")
                    && (CRSettings.myPrefs.natureVigil == CRSettings.CooldownPrefs.OnCoolDown
                    || (CRSettings.myPrefs.natureVigil == CRSettings.CooldownPrefs.Bosses && IsWoWBoss(Me.CurrentTarget))))
                );
        }
        #endregion Buffs

        #region predatoryheal
        Composite useHealingTouchOnOthers()
        {
            return new Action(ret =>
                {
                    WoWUnit myTarget = GetHealTarget(39);

                    if (myTarget != null && Me.HealthPercent >= CRSettings.myPrefs.predatoryPercent && !myTarget.IsMe)
                    {
                        if (SpellManager.CanCast("Healing Touch"))
                        {
                            SpellManager.Cast("Healing Touch", myTarget);
                            LastSpell = "Healing Touch";
                            LogMsg("Healing Touch on " + myTarget + " with Predatory Swiftness Proc", 4);
                        }
                    }
                    else
                    {
                        if (SpellManager.CanCast("Healing Touch"))
                        {
                            SpellManager.Cast("Healing Touch", Me);
                            LastSpell = "Healing Touch";
                            LogMsg("Healing Touch on myself with Predatory Swiftness Proc", 4);
                        }
                    }
                });
        }

        public WoWUnit GetHealTarget(double range)
        {
            return (from unit in ObjectManager.GetObjectsOfTypeFast<WoWPlayer>()
                    orderby unit.HealthPercent ascending
                    where ((unit.IsInMyPartyOrRaid || unit.IsMe)
                    && unit.HealthPercent <= CRSettings.myPrefs.otherPredatoryPercent
                    && !unit.IsDead
                    && !unit.IsGhost
                    && unit.IsFriendly
                    && unit.Distance - unit.CombatReach - 1 <= range
                    && unit.InLineOfSpellSight)
                    select unit).FirstOrDefault();
        }

        #endregion predatoryheal

        #region spellcasting
        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me.CurrentTarget);
                        LogMsg(descr, kleur);
                        LastSpell = spell;
                    }
                    ));
        }
        Composite Cast(int spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me.CurrentTarget);
                        LogMsg(descr, kleur);
                        LastSpelID = spell;
                    }
            ));
        }
        Composite CastBuff(string spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        LogMsg(descr, kleur);
                        LastSpell = spell;
                    }
                    ));
        }
        Composite CastBuff(int spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        LogMsg(descr, kleur);
                        LastSpelID = spell;
                    }
            ));
        }
        #endregion spellcasting

        #region find MotwTargets
        public WoWUnit getMotWTarget(double range)
        {
            return (from unit in ObjectManager.GetObjectsOfTypeFast<WoWPlayer>()
                    where ((unit.IsInMyPartyOrRaid || unit.IsMe)
                        && !buffExists("Mark of the Wild", unit)
                        && !buffExists("Legacy of the Emperor", unit)
                        && !buffExists("Blessing of Kings", unit)
                        && !buffExists("Embrace of the Shale Spider", unit)
                        && !unit.IsDead
                        && !unit.IsGhost
                        && unit.IsFriendly
                        && unit.Distance - unit.CombatReach - 1 <= range
                        && unit.InLineOfSpellSight)
                    select unit).FirstOrDefault();
        }
        Composite castMotW()
        {
            return new Decorator(
                new Action(ret =>
                    {
                        WoWUnit myTarget = getMotWTarget(39);

                        if (myTarget != null || myTarget.IsMe)
                        {
                            var motwChoice = CRSettings.myPrefs.motw.ToString();

                            switch (motwChoice)
                            {
                                case "Always":
                                    if (!buffExists("Mark of the Wild", myTarget)
                                        && !buffExists("Legacy of the Emperor", myTarget)
                                        && !buffExists("Blessing of Kings", myTarget)
                                        && !buffExists("Embrace of the Shale Spider", myTarget)
                                        && !Me.Mounted
                                        && Me.Shapeshift != ShapeshiftForm.FlightForm
                                        && !Me.IsFlying)
                                    {
                                        if (SpellManager.CanCast("Mark of the Wild"))
                                        {
                                            SpellManager.Cast("Mark of the Wild", myTarget);
                                            LogMsg("Mark of the Wild on " + myTarget, 0);
                                        }
                                    }
                                    break;
                                case "AlwaysButNotInCombat":
                                    if (!buffExists("Mark of the Wild", myTarget)
                                        && !buffExists("Legacy of the Emperor", myTarget)
                                        && !buffExists("Blessing of Kings", myTarget)
                                        && !buffExists("Embrace of the Shale Spider", myTarget)
                                        && !Me.Combat
                                        && !Me.Mounted
                                        && Me.Shapeshift != ShapeshiftForm.FlightForm
                                        && !Me.IsFlying)
                                    {
                                        if (SpellManager.CanCast("Mark of the Wild"))
                                        {
                                            SpellManager.Cast("Mark of the Wild", myTarget);
                                            LogMsg("Mark of the Wild on " + myTarget, 0);
                                        }
                                    }
                                    break;
                                case "NotInParty":
                                    if (!buffExists("Mark of the Wild", Me)
                                        && !Me.Mounted
                                        && Me.Shapeshift != ShapeshiftForm.FlightForm
                                        && !Me.IsFlying)
                                    {
                                        if (SpellManager.CanCast("Mark of the Wild"))
                                        {
                                            SpellManager.Cast("Mark of the Wild", Me);
                                            LogMsg("Mark of the Wild on " + StyxWoW.Me, 0);
                                        }
                                    }
                                    break;
                            }
                        }
                    }
            ));
        }
        #endregion find MotwTargets

        #region rooted
        public bool MeRooted()
        {
            WoWAuraCollection Auras = StyxWoW.Me.GetAllAuras();
            foreach (WoWAura aura in Auras)
            {
                if (!aura.IsHarmful) { return false; }

                if (aura.Spell.Mechanic == WoWSpellMechanic.Slowed
                || aura.Spell.Mechanic == WoWSpellMechanic.Dazed
                || aura.Spell.Mechanic == WoWSpellMechanic.Frozen
                || aura.Spell.Mechanic == WoWSpellMechanic.Incapacitated
                || aura.Spell.Mechanic == WoWSpellMechanic.Rooted
                || aura.Spell.Mechanic == WoWSpellMechanic.Shackled)
                {
                    return true;
                }
            }
            return false;
        }
        Composite MeIsRooted()
        {
            return new Action(ret =>
            {
                if (Me.Shapeshift == ShapeshiftForm.Cat)
                {
                    SpellManager.Cast("Cat Form", Me);
                }
                if (Me.Shapeshift == ShapeshiftForm.Bear)
                {
                    SpellManager.Cast("Bear Form", Me);
                }
                if (Me.Shapeshift == ShapeshiftForm.Normal
                    && SpellManager.HasSpell("Cat Form"))
                {
                    SpellManager.Cast("Cat Form", Me);
                }
            });
        }
        #endregion rooted

        #region wildcharge
        public bool targetDistanceBetween(int left, int right)
        {
            return Me.CurrentTarget.Distance >= left && Me.CurrentTarget.Distance <= right;
        }
        #endregion wildcharge

        #region resting
        public bool healthpercentBetween(int left, int right)
        {
            return Me.HealthPercent >= left && Me.HealthPercent <= right;
        }
        #endregion resting

        #region pull
        Composite pullWildCharge()
        {
            return new Action(ret =>
            {
                if (gotTarget && !targetDistanceBetween(8, 25))
                {
                    moveControlls(24);
                }
                if (SpellManager.CanCast("Wild Charge"))
                {
                    SpellManager.Cast("Wild Charge", Me.CurrentTarget);
                    LogMsg("Wild Charge", 1);
                    LastSpell = "Wild Charge";
                }
            });
        }
        Composite pullFaerieFire()
        {
            return new Action(ret =>
            {
                if (gotTarget && Me.CurrentTarget.Distance > 35)
                {
                    moveControlls(35);
                }
                if (!SpellManager.HasSpell("Faerie Swarm")
                    && SpellManager.HasSpell("Faerie Fire")
                    && SpellManager.CanCast("Faerie Fire")
                    && !spellOnCooldown("Faerie Fire"))
                {
                    SpellManager.Cast("Faerie Fire", Me.CurrentTarget);
                    LogMsg("Faerie Fire", 1);
                    LastSpell = "Faerie Fire";
                }
                if (SpellManager.HasSpell("Faerie Swarm")
                    && SpellManager.CanCast("Faerie Swarm")
                    && !spellOnCooldown("Faerie Swarm"))
                {
                    SpellManager.Cast("Faerie Swarm", Me.CurrentTarget);
                    LogMsg("Faerie Swarm", 1);
                    LastSpell = "Faerie Swarm";
                }
            });
        }
        Composite pullMoonfireWrath()
        {
            return new Action(ret =>
            {
                if (gotTarget && Me.CurrentTarget.Distance > 35)
                {
                    moveControlls(35);
                }
                if (SpellManager.HasSpell("Moonfire")
                    && SpellManager.CanCast("Moonfire"))
                {
                    SpellManager.Cast("Moonfire", Me.CurrentTarget);
                    LogMsg("Moonfire", 1);
                    LastSpell = "Moonfire";
                }
                if (!SpellManager.HasSpell("Moonfire")
                    && SpellManager.CanCast("Wrath"))
                {
                    SpellManager.Cast("Wrath", Me.CurrentTarget);
                    LogMsg("Wrath", 1);
                    LastSpell = "Wrath";
                }
            });
        }
        Composite pullRake()
        {
            return new Action(ret =>
            {
                if (gotTarget && Me.CurrentTarget.Distance > 5)
                {
                    moveControlls(5);
                }
                if (SpellManager.HasSpell("Rake")
                    && Me.EnergyPercent >= 35
                    && Me.CurrentTarget.IsWithinMeleeRange
                    && SpellManager.CanCast("Rake"))
                {
                    SpellManager.Cast("Rake", Me.CurrentTarget);
                    LogMsg("Rake", 1);
                    LastSpell = "Rake";
                }
            });
        }
        Composite pullPounce()
        {
            return new Action(ret =>
            {
                if (Me.CurrentTarget.Distance > 5)
                {
                    moveControlls(5);
                }
                if (SpellManager.HasSpell("Pounce")
                    && Me.EnergyPercent >= 50
                    && Me.CurrentTarget.IsWithinMeleeRange
                    && SpellManager.CanCast("Pounce"))
                {
                    SpellManager.Cast("Pounce");
                    LogMsg("Pounce", 1);
                    LastSpell = "Pounce";
                }
            });
        }
        #endregion pull

        #region pounce
        public bool usePounce
        {
            get
            {
                if (CRSettings.myPrefs.pounce
                    && SpellManager.HasSpell("Prowl")
                    && SpellManager.HasSpell("Pounce")
                    && buffExists("Prowl", Me)
                    && Me.EnergyPercent >= 50)
                {
                    return true;
                }
                return false;
            }
        }
        #endregion pounce

        #region logs
        public void LogMsg(string msg, int kleurtje)
        {
            Color kleur = Colors.Yellow;
            switch (kleurtje)
            {
                case 0:
                    kleur = Colors.Orange;
                    break;
                case 1:
                    kleur = Colors.PaleGreen;
                    break;
                case 2:
                    kleur = Colors.BlanchedAlmond;
                    break;
                case 3:
                    kleur = Colors.Yellow;
                    break;
                case 4:
                    kleur = Colors.Red;
                    break;
                case 5:
                    kleur = Colors.CornflowerBlue;
                    break;
            }
            Logging.Write(kleur, msg);
        }
        #endregion logs

        #region SavageRoar
        public bool useSavageRoar
        {
            get
            {
                if (SpellManager.HasSpell("Savage Roar")
                    && SpellManager.HasSpell(RIP)
                    && debuffTimeLeft(RIP, Me.CurrentTarget) <= 5000
                    && Me.ComboPoints >= 4)
                {
                    return false;
                }
                return true;
            }
        }
        #endregion SavageRoar

        #region AddCounting
        private int addCount
        {
            get
            {
                int count = 0;
                foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
                {
                    if (gotTarget
                        && u.CanSelect
                        && !u.IsPlayer
                        && u.IsAlive
                        && u.Guid != Me.Guid
                        && !u.IsFriendly
                        && u.IsHostile
                        && u.Attackable
                        && !u.IsTotem
                        && !u.IsCritter
                        && !u.IsNonCombatPet
                        && (u.Location.Distance(Me.CurrentTarget.Location) <= 8 || u.Location.Distance2D(Me.CurrentTarget.Location) <= 8))
                    {
                        count++;
                    }
                }
                return count;
            }
        }
        #endregion AddCounting

        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {

            if (gotTarget
                && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
            {
                return true;
            }
            else if (gotTarget
                && target.IsBoss(mytarget))
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.MaxHealth >= (65 * 1000000))
            {
                return true;
            }
            else if (gotTarget
                    && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettings.myPrefs.ElitesHealth)
                    && !Me.IsInInstance
                    && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                     && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                     && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettings.myPrefs.ElitesHealth)
                     && !Me.IsInInstance
                     && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettings.myPrefs.ElitesHealth)
                && !Me.IsInInstance
                && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.Name.Contains("Training Dummy")
                && !Me.IsInInstance)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.IsPlayer
                && !Me.CurrentTarget.IsFriendly)
            {
                return true;
            }
            return false;
        }

        #endregion Kind of Target

        #region movement etc .....

        public void MoveInRange(float range)
        {
            LogMsg("Moving in Range (" + range + ")" + " " + Me.CurrentTarget.Name, 5);

            while (gotTarget && Me.CurrentTarget.Distance > range)
            {
                Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
            }
        }
        public void MoveInLignOfSfght()
        {
            LogMsg("Moving in lign of sight " + Me.CurrentTarget.Name, 5);

            while (gotTarget && !Me.CurrentTarget.InLineOfSight)
            {
                Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
            }
        }
        public void Facing()
        {
            if (gotTarget && !Me.IsSafelyFacing(Me.CurrentTarget))
            {
                Me.CurrentTarget.Face();
            }
        }
        Composite targetFacing()
        {
            return new Action(ret =>
            {
                Navigator.PlayerMover.MoveStop();
                Me.CurrentTarget.Face();
            });
        }
        Composite moveControlls(float rangeDistance)
        {
            return new Action(ret =>
            {
                if (gotTarget
                    && Me.CurrentTarget.Distance > rangeDistance
                    && CRSettings.myPrefs.Movement)
                {
                    MoveInRange(rangeDistance);
                    Navigator.PlayerMover.MoveStop();
                }
                if (gotTarget
                    && CRSettings.myPrefs.Movement
                    && !Me.CurrentTarget.InLineOfSight)
                {
                    MoveInLignOfSfght();
                    Navigator.PlayerMover.MoveStop();
                }
                if (gotTarget
                    && CRSettings.myPrefs.Facing
                    && !Me.IsSafelyFacing(Me.CurrentTarget))
                {
                    Navigator.PlayerMover.MoveStop();
                    Me.CurrentTarget.Face();
                }
            });
        }
        public bool checkRange(float rangeDistance)
        {
            if (Me.CurrentTarget.Distance >= rangeDistance)
            {
                return false;
            }
            return true;
        }
        #endregion movement etc ....

        #region virmenpotions
        Composite useVirmenPotion()
        {
            return new Action(ret =>
            {
                WoWItem potion = Me.BagItems.FirstOrDefault(h => h.Entry == 76089);

                if (potion == null)
                {
                    return;
                }
                if (potion != null && potion.CooldownTimeLeft.TotalMilliseconds <= 0)
                {
                    potion.Use();
                    Logging.Write(Colors.BlanchedAlmond, "Using " + potion.Name);
                }
            });
        }
        #endregion virmenpotions

        #region trinket1
        Composite useTrinket1()
        {
            return new Action(ret =>
                {
                    var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;

                    if (firstTrinket != null && CanUseEquippedItem(firstTrinket))
                    {
                        firstTrinket.Use();
                        LogMsg("Using 1st trinket", 8);
                    }
                });
        }
        #endregion trinket1

        #region trinket2
        Composite useTrinket2()
        {
            return new Action(ret =>
                {
                    var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;

                    if (secondTrinket != null && CanUseEquippedItem(secondTrinket))
                    {
                        secondTrinket.Use();
                        LogMsg("Using 2nd trinket", 8);
                    }
                });
        }
        #endregion trinket2

        #region engineer gloves
        Composite useEngiGloves()
        {
            return new Action(ret =>
            {
                var engiGloves = StyxWoW.Me.Inventory.Equipped.Hands;

                if (engiGloves != null && CanUseEquippedItem(engiGloves))
                {
                    engiGloves.Use();
                    LogMsg("Using Engineer Gloves", 8);
                }
            });
        }
        #endregion engineer gloves

        #region healthstone
        Composite useHealthStone()
        {
            return new Action(ret =>
            {
                WoWItem hstone = Me.BagItems.FirstOrDefault(h => h.Entry == 5512);
                if (hstone == null)
                {
                    return;
                }
                if (hstone != null && hstone.CooldownTimeLeft.TotalMilliseconds <= 0)
                {
                    hstone.Use();
                    Logging.Write(Colors.BlanchedAlmond, "Using Healthstone");
                }
            });
        }
        #endregion healthstone

        #region flask
        Composite useFlask()
        {
            return new Action(ret =>
                {
                    WoWItem flask = Me.BagItems.FirstOrDefault(h => h.Entry == 76084);
                    if (flask == null)
                    {
                        return;
                    }
                    if (flask != null && flask.CooldownTimeLeft.TotalMilliseconds <= 0)
                    {
                        flask.Use();
                        Logging.Write(Colors.BlanchedAlmond, "Using " + flask.Name);
                    }
                });
        }
        #endregion flask

        #region alchemy flask
        Composite useAlchemyFlask()
        {
            return new Action(ret =>
                {
                    WoWItem alchflask = Me.BagItems.FirstOrDefault(h => h.Entry == 75525);

                    if (alchflask != null)
                    {
                        alchflask.Use();
                        Logging.Write(Colors.LightBlue, "Using Alchemist's Flask");
                    }
                });
        }
        #endregion alchemy flask

        #region can use equipped items
        private static bool CanUseEquippedItem(WoWItem item)
        {
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
            {
                return false;
            }
            return item.Usable && item.Cooldown <= 0;
        }
        #endregion can use equipped items

        #region pause


        public bool Paused = false;
        public bool SwitchBearForm = false;
        public bool PauseAoe = false;

        public override void ShutDown()
        {
            Lua.Events.DetachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
        }

        private void HandleModifierStateChanged(object sender, LuaEventArgs args)
        {
            if (CRSettings.myPrefs.PauseKeys == CRSettings.Keypress.None
                && CRSettings.myPrefs.BearFormKeys == CRSettings.Keypress.None
                && CRSettings.myPrefs.AoePauseKeys == CRSettings.Keypress.None)
            {
                return;
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                string aoePause = "Aoe cancelled, press " + CRSettings.myPrefs.AoePauseKeys.ToString() + " in WOW again to resume Aoe";

                if (args.Args[0].ToString() == CRSettings.myPrefs.AoePauseKeys.ToString())
                {
                    PauseAoe = !PauseAoe;
                    if (PauseAoe)
                    {
                        Logging.Write("Aoe cancelled, press {0} in WOW again to resume Aoe",
                                     CRSettings.myPrefs.AoePauseKeys.ToString());
                        if (CRSettings.myPrefs.PrintMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + aoePause + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Aoe Resumed");
                        if (CRSettings.myPrefs.PrintMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Aoe Resumed !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == CRSettings.myPrefs.BearFormKeys.ToString())
                {
                    SwitchBearForm = !SwitchBearForm;
                    if (SwitchBearForm)
                    {
                        string backBear = "Switching to Bear Form, press " + CRSettings.myPrefs.BearFormKeys.ToString() + " in WOW again to switch back to Cat Form";

                        Logging.Write("Switching to Bear Form, press {0} in WOW again to switch back to Cat Form",
                                     CRSettings.myPrefs.BearFormKeys.ToString());
                        if (CRSettings.myPrefs.PrintMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + backBear + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Switching back to Cat Form !");
                        if (CRSettings.myPrefs.PrintMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Switching back to Cat Form !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == CRSettings.myPrefs.PauseKeys.ToString())
                {
                    string pauseCR = "CR paused, press " + CRSettings.myPrefs.PauseKeys.ToString() + " in WOW again to turn back on";
                    Paused = !Paused;
                    if (Paused)
                    {
                        Logging.Write("CR paused, press {0} in WOW again to turn back on",
                                     CRSettings.myPrefs.PauseKeys.ToString());
                        if (CRSettings.myPrefs.PrintMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseCR + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("CR running again ....");
                        if (CRSettings.myPrefs.PrintMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"CR running again ....\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
        }
        #endregion pause

        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion

        #region Target Checks

        internal IEnumerable<WoWUnit> attackableTargets
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(U => U.Attackable && U.CanSelect && !U.IsFriendly && !U.IsDead && !U.IsNonCombatPet && !U.IsCritter); }
        }
        public bool gotTarget { get { return Me.GotTarget && Me.CurrentTarget != null && Me.CurrentTarget.Attackable && (!Me.CurrentTarget.IsDead && !Me.CurrentTarget.IsFriendly || isTargetDummy); } }

        public bool isTargetDummy { get { return Me.CurrentTarget.Name == "Training Dummy" || Me.CurrentTarget.Name == "Raider's Training Dummy"; } }

        internal IEnumerable<WoWUnit> nearbyTargets(WoWPoint fromLocation, double Radius)
        {
            var Hostile = attackableTargets;
            var maxDistance = Radius * Radius;
            return Hostile.Where(x => x.Location.DistanceSqr(fromLocation) < maxDistance);
        }
        public double targetDistance(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.DistanceSqr;
                if (Results != null)
                    return onTarget.DistanceSqr;
            }
            return 0;
        }
        public double targetHP(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.HealthPercent;
                if (Results != null)
                    return onTarget.HealthPercent;
            }
            return 0;
        }
        #endregion

        #region Timer Checks
        private int conv_Date2Timestam(DateTime _time)
        {
            var date1 = new DateTime(1970, 1, 1);
            DateTime date2 = _time;
            var ts = new TimeSpan(date2.Ticks - date1.Ticks);
            return (Convert.ToInt32(ts.TotalSeconds));
        }
        private uint current_life;
        private int current_time;
        private ulong guid;
        private uint first_life;
        private uint first_life_max;
        private int first_time;
        public long targetExistence(WoWUnit onTarget)
        {
            if (onTarget == null) return 0;
            if (isTargetDummy) return 9999;
            if (onTarget.CurrentHealth == 0 || onTarget.IsDead || !onTarget.IsValid || !onTarget.IsAlive)
                return 0;
            if (guid != onTarget.Guid)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
            }
            current_life = onTarget.CurrentHealth;
            current_time = conv_Date2Timestam(DateTime.Now);
            var time_diff = current_time - first_time;
            var hp_diff = first_life - current_life;
            if (hp_diff > 0)
            {
                var full_time = time_diff * first_life_max / hp_diff;
                var past_first_time = (first_life_max - first_life) * time_diff / hp_diff;
                var calc_time = first_time - past_first_time + full_time - current_time;
                if (calc_time < 1) calc_time = 99;
                var time_to_die = calc_time;
                var fight_length = full_time;
                return time_to_die;
            }
            if (hp_diff < 0)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
                return -1;
            }
            if (current_life == first_life_max)
                return 9999;
            return -1;
        }
        #endregion

        #region get target
        private void FindTarget()
        {
            WoWUnit newTarget = (from o in ObjectManager.ObjectList
                                 where o is WoWUnit
                                 let unit = o.ToUnit()
                                 where unit.Distance <= 40
                                     && unit.Attackable
                                     && unit.IsAlive
                                     && unit.IsHostile
                                     && !unit.IsFriendly
                                     && !unit.IsPet
                                     && !unit.IsPetBattleCritter
                                     && !Blacklist.Contains(unit.Guid, BlacklistFlags.All)
                                 orderby unit.Distance ascending
                                 select unit
                                 ).FirstOrDefault();

            if (newTarget.Name.Length < 2)
            {
                return;
            }
            else
            {
                newTarget.Target();
                LogMsg("Atacking " + newTarget.Name, 4);
                return;
            }
        }
        #endregion get target














        #endregion einde Helpers
    }
}
